/*
 * File name: WatermarkPageView.java
 * 
 * Description: The watermark page overlay on camera preview.
 *
 * Author: Theobald_wu, contact with wuqizhi@tydtech.com
 * 
 * Date: 2014-6-25   
 * 
 * Copyright (C) 2014 TYD Technology Co.,Ltd.
 * 
 * 
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package com.freeme.cameraplugin.watermarkmode.ui;

import android.animation.ValueAnimator;
import android.app.AlertDialog;
import android.app.Service;
import android.content.Context;
import android.content.DialogInterface;
import android.content.res.Configuration;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.DashPathEffect;
import android.graphics.Matrix;
import android.graphics.Paint;
import android.graphics.Rect;
import android.graphics.RectF;
import android.graphics.drawable.Drawable;
import android.os.Vibrator;
import android.text.Editable;
import android.text.InputFilter;
import android.text.Spannable;
import android.text.SpannableStringBuilder;
import android.text.TextWatcher;
import android.text.style.ForegroundColorSpan;
import android.util.Log;
import android.view.LayoutInflater;
import android.view.Gravity;
import android.view.MotionEvent;
import android.view.View;
import android.view.ViewConfiguration;
import android.view.inputmethod.InputMethodManager;
import android.widget.EditText;
import android.widget.ImageView;
import android.widget.TextView;
import com.freeme.cameraplugin.watermarkmode.R;
import com.freeme.cameraplugin.watermarkmode.WatermarkMode;
import com.freeme.cameraplugin.watermarkmode.model.WatermarkItemInfo;
import com.freeme.cameraplugin.watermarkmode.utils.WatermarkUtil;
import com.freeme.camera.CameraPluginUtil;
import com.freeme.camera.ICameraExt;
import java.text.SimpleDateFormat;
import java.util.Date;
import android.graphics.Bitmap;

public class WatermarkPageView extends ImageView {
    private static final String TAG = "[TYD_DEBUG]WatermarkPageView";
    private static final int LONG_PRESS_TIMEOUT = 1000;
    private static final int PROMPT_RECT_APPEAR_DURATION = 8000;
    private final int EDIT_TEXT_MAX_LENGTH;

    private static final int IDLE = 0;
    private static final int TAP_DOWN = 1;
    private static final int LONG_CLICK = 2;
    private static final int DRAG = 3;

    private ICameraExt mCamera;
    private int mWatermarkIndex; // the index of watermark arrays
    private boolean mIsEditNote;
    private String mEditNoteText;
    private int mState = IDLE;
    private float mTranslationX;
    private float mTranslationY;
    private int mDownX;
    private int mDownY;
    private int mLastX;
    private int mLastY;
    private int mTouchSlop;
    // watermark body bound of preview
    private Rect mPreviewBodyBound = new Rect();
    // the edited not bound
    private Rect mEditNoteArea;
    private Paint mEditRectPaint;
    private ValueAnimator mPromptEditAnim;
    private int mInputCountColor;
    private WatermarkItemInfo mItemInfo;
    private WatermarkMode mWatermarkMode;
    private Context mContext;

    public WatermarkPageView(Context context, WatermarkMode mode, ICameraExt cameraExt) {
        super(context);
        mCamera = cameraExt;
        mContext = context;
        mWatermarkMode = mode;
        final ViewConfiguration configuration = ViewConfiguration.get(context);
        mTouchSlop = configuration.getScaledTouchSlop();

        mEditRectPaint = new Paint(Paint.ANTI_ALIAS_FLAG);
        mEditRectPaint.setColor(Color.argb(255, 255, 255, 255));
        mEditRectPaint.setStyle(Paint.Style.STROKE);
        mEditRectPaint.setStrokeWidth(CameraPluginUtil.dpToPixel(mContext, 2));
        mEditRectPaint.setPathEffect(new DashPathEffect(new float[] {
                CameraPluginUtil.dpToPixel(mContext, 6), CameraPluginUtil.dpToPixel(mContext, 6)
        }, 1));

        mPromptEditAnim = new ValueAnimator();
        mPromptEditAnim.setDuration(PROMPT_RECT_APPEAR_DURATION);
        mPromptEditAnim.setFloatValues(0, 1);

        EDIT_TEXT_MAX_LENGTH = getContext().getResources().getInteger(
                R.integer.watermark_note_max_length);
        mInputCountColor = getContext().getResources().getColor(R.color.theme_color);
    }

    public void setWatermarkIndex(int index) {
        if (mWatermarkIndex != index) {
            mWatermarkIndex = index;
            mEditNoteText = null;
        }
    }

    public void setWatermarkItemInfo(WatermarkItemInfo info) {
        mItemInfo = info;
        mEditNoteText = null;
        invalidate();
    }

    public WatermarkItemInfo getWatermarkItemInfo() {
        return mItemInfo;
    }

    public void onSelected() {
        if (mPromptEditAnim.isRunning()) {
            mPromptEditAnim.cancel();
        }

        mPromptEditAnim.start();
        invalidate();
    }

    public boolean isIdle() {
        return (mState == IDLE);
    }

    @Override
    public boolean dispatchTouchEvent(MotionEvent event) {
        // TODO Auto-generated method stub
        return super.dispatchTouchEvent(event);
    }

    public View getOutputPanel(int cameraOri) {
        // int cameraOri = mCamera.getOrientationCompensation();
        // inflate layout
        int layout = mItemInfo.layoutId;
        if (layout == 0) {
            throw new IllegalStateException("watermark layout is illegal! watermark index = "
                    + mWatermarkIndex);
        }

        RotateLayout panel = (RotateLayout) LayoutInflater.from(getContext()).inflate(layout, null);
        // set orientation
        panel.setOrientation(cameraOri, false);
        parseLayout(panel, layout, mWatermarkIndex);

        // make sure measure and layout
        int orientation = getContext().getResources().getConfiguration().orientation;
        boolean isLandScape = Configuration.ORIENTATION_LANDSCAPE == orientation;
        Log.i(TAG, "isLandScape = " + isLandScape);
        int w = WatermarkMode.OUTPUT_IMAGE_WIDTH_IDEAL;
        int h = WatermarkMode.OUTPUT_IMAGE_HEIGHT_IDEAL;
        if (isLandScape) {
            w = WatermarkMode.OUTPUT_IMAGE_HEIGHT_IDEAL;
            h = WatermarkMode.OUTPUT_IMAGE_WIDTH_IDEAL;
        }

        int widthSpec = MeasureSpec.makeMeasureSpec(w, MeasureSpec.EXACTLY);
        int heightSpec = MeasureSpec.makeMeasureSpec(h, MeasureSpec.EXACTLY);
        panel.measure(widthSpec, heightSpec);
        panel.layout(0, 0, w, h);

        // move preview body
        View body = panel.findViewById(R.id.body);
        // do not over by panel'bounds
        int areaW = w;
        int areaH = h;
        if (cameraOri % 180 != 0) {
            areaW = h;
            areaH = w;
        }

        if (body.getRight() + mTranslationX > areaW) {
            mTranslationX = areaW - body.getRight();
        } else if (body.getLeft() + mTranslationX < 0) {
            mTranslationX = -body.getLeft();
        }
        if (body.getBottom() + mTranslationY > areaH) {
            mTranslationY = areaH - body.getBottom();
        } else if (body.getTop() + mTranslationY < 0) {
            mTranslationY = -body.getTop();
        }
        body.setTranslationX(mTranslationX);
        body.setTranslationY(mTranslationY);

        return panel;
    }

    private void drawDashRect(Canvas canvas) {
        if (mEditNoteArea != null) {
            // get alpha
            float t = (Float) mPromptEditAnim.getAnimatedValue();
            int alpha = (int) (Math.sin(Math.PI * t) * 0xFF);
            alpha = Math.min(alpha, 0xFF);

            canvas.save();
            mEditRectPaint.setAlpha(alpha);
            canvas.drawRect(mEditNoteArea, mEditRectPaint);
            canvas.restore();

            invalidate();
        }
    }

    @Override
    protected void onDraw(Canvas canvas) {
        // preview scale relative watermark layout(600W pixels)
        float previewScale = mWatermarkMode.getPreviewScale();
        View panel = createPanel();

        canvas.save();
        canvas.scale(previewScale, previewScale);
        panel.draw(canvas);
        canvas.restore();

        Log.i(TAG, "canvas width = " + canvas.getWidth() + "canvas height = " + canvas.getHeight()
                + "previewScale = " + previewScale);

        // draw rectangle prompt here is editable.
        if (mPromptEditAnim.isRunning()) {
            drawDashRect(canvas);
        }
    }

    @Override
    public boolean onTouchEvent(MotionEvent e) {
        boolean result = false;
        int action = e.getActionMasked();
        int x = (int) e.getX();
        int y = (int) e.getY();
        int w = Math.min(getMeasuredWidth(), getMeasuredHeight());

        if (!(mWatermarkMode.isEnabled())) {
            return false;
        }

        switch (action) {
            case MotionEvent.ACTION_DOWN:
                Log.i(TAG, "onTouch() down: x = " + x + ", y = " + y + ", w = " + w);
                if (IDLE == mState && mPreviewBodyBound.contains(x, y)) {
                    mState = TAP_DOWN;
                    mDownX = mLastX = x;
                    mDownY = mLastY = y;
                    checkForLongPress();
                    result = true;
                }
                break;

            case MotionEvent.ACTION_UP:
                if (TAP_DOWN == mState) {
                    // edit note
                    if (mIsEditNote) {
                        inputNoteDialog();
                    } else {
                        // mCamera.getWatermarkManager().popupSettingPanel();
                    }
                    result = true;
                }

                // touch focus
                if (IDLE == mState) {
                    // onTouchFocus(e.getX(), e.getY());
                }
                resetState();
                break;

            case MotionEvent.ACTION_MOVE: {
                // after long click, start dragging
                if (LONG_CLICK == mState || DRAG == mState) {
                    boolean xMoved = Math.abs(x - mDownX) > mTouchSlop;
                    boolean yMoved = Math.abs(y - mDownY) > mTouchSlop;

                    if (xMoved || yMoved) {
                        // drag preview of watermark
                        int offsetX = x - mLastX;
                        int offsetY = y - mLastY;
                        float scale = mWatermarkMode.getPreviewScale();

                        mTranslationX += offsetX / scale;
                        mTranslationY += offsetY / scale;
                        mLastX = x;
                        mLastY = y;
                        mState = DRAG;
                        result = true;
                        invalidate();
                    }
                }

                break;
            }

            case MotionEvent.ACTION_CANCEL:
                resetState();
                break;

            default:
                break;
        }

        if (LONG_CLICK == mState || DRAG == mState) {
            result = true;
        }

        return result;
    }

    private View createPanel() {
        // inflate layout
        int layout = mItemInfo.layoutId;
        if (layout == 0) {
            throw new IllegalStateException("watermark layout is illegal! watermark index = "
                    + mWatermarkIndex);
        }

        LayoutInflater inflater = LayoutInflater.from(mContext);
        View panel = inflater.inflate(layout, null);
        parseLayout(panel, layout, mWatermarkIndex);

        // make sure measure and layout
        int orientation = getContext().getResources().getConfiguration().orientation;
        boolean isLandScape = Configuration.ORIENTATION_LANDSCAPE == orientation;
        int cameraOri = mCamera.getOrientation();
        int w = WatermarkMode.OUTPUT_IMAGE_WIDTH_IDEAL;
        int h = WatermarkMode.OUTPUT_IMAGE_HEIGHT_IDEAL;

        if (isLandScape) {
            w = WatermarkMode.OUTPUT_IMAGE_HEIGHT_IDEAL;
            h = WatermarkMode.OUTPUT_IMAGE_WIDTH_IDEAL;
        }
        if (cameraOri % 180 != 0 && cameraOri != -1) {
            int temp = w;
            w = h;
            h = temp;
        }

        int widthSpec = MeasureSpec.makeMeasureSpec(w, MeasureSpec.EXACTLY);
        int heightSpec = MeasureSpec.makeMeasureSpec(h, MeasureSpec.EXACTLY);
        panel.measure(widthSpec, heightSpec);
        panel.layout(0, 0, w, h);

        // move preview body
        View body = panel.findViewById(R.id.body);
        // do not over by panel'bounds
        if (body.getRight() + mTranslationX > w) {
            mTranslationX = w - body.getRight();
        } else if (body.getLeft() + mTranslationX < 0) {
            mTranslationX = -body.getLeft();
        }
        if (body.getBottom() + mTranslationY > h) {
            mTranslationY = h - body.getBottom();
        } else if (body.getTop() + mTranslationY < 0) {
            mTranslationY = -body.getTop();
        }
        Log.i(TAG, "createPanel(): mTranslationX = " + mTranslationX + ", mTranslationY = "
                + mTranslationY + ", panel width = " + panel.getMeasuredWidth()
                + ", panel height = " + panel.getMeasuredHeight() + ", mWatermarkIndex = "
                + mWatermarkIndex + ", preview scale = " + mWatermarkMode.getPreviewScale());
        body.setTranslationX(mTranslationX);
        body.setTranslationY(mTranslationY);

        // get preview body bound
        getPreviewItemBounds(body, mPreviewBodyBound);

        // get edited note bound
        View note = panel.findViewById(R.id.note);
        if (note != null) {
            mEditNoteArea = new Rect();
            getPreviewItemBounds(note, mEditNoteArea);
            mEditNoteArea.offset(mPreviewBodyBound.left, mPreviewBodyBound.top);
        } else {
            mEditNoteArea = null;
        }

        return panel;
    }

    private void parseLayout(View root, int layout, int index) {
        Log.i(TAG, "layout = " + layout + "index" + index);
        mIsEditNote = false;
        switch (layout) {
            case R.layout.watermark_template_0:
            case R.layout.watermark_template_1:
            case R.layout.watermark_template_2:
            case R.layout.watermark_template_3:
                // set main part
                int mainpart = mItemInfo.primitiveId;
                ImageView image = (ImageView) root.findViewById(R.id.mainpart);
                Log.i(TAG, mainpart + "");
                if (mainpart != 0) {
                    image.setImageResource(mainpart);
                } else {
                    image.setImageBitmap(WatermarkUtil.getBitmapByFileUrl(mItemInfo.primitiveUrl));
                }

                break;

            case R.layout.watermark_template_4:
                // set note
                int note4 = mItemInfo.promptId;
                TextView noteView4 = (TextView) root.findViewById(R.id.note);
                if (mItemInfo.primitiveId != 0) {
                    noteView4.setBackgroundResource(mItemInfo.primitiveId);
                } else {
                    noteView4.getBackground();
                    Bitmap bitmap = WatermarkUtil.getBitmapByFileUrl(mItemInfo.primitiveUrl);
                    if (bitmap != null) {
                        Drawable drawable = WatermarkUtil.bitmapToNinePatchDrawable(mContext,
                                bitmap);
                        noteView4.setBackgroundDrawable(drawable);
                    }
                }
                if (mEditNoteText != null) {
                    noteView4.setText(mEditNoteText);
                } else {
                    if (note4 != 0) {
                        noteView4.setText(note4);
                    } else {
                        noteView4.setText(mItemInfo.prompt);
                    }
                    mEditNoteText = noteView4.getText().toString();
                }
                mIsEditNote = true;
                break;

            case R.layout.watermark_template_5:
                int note5 = mItemInfo.promptId;
                TextView noteView5 = (TextView) root.findViewById(R.id.note);
                if (mEditNoteText != null) {
                    noteView5.setText(mEditNoteText);
                } else {
                    if (note5 != 0) {
                        noteView5.setText(note5);
                    } else {
                        noteView5.setText(mItemInfo.prompt);
                    }
                    mEditNoteText = noteView5.getText().toString();
                }
                mIsEditNote = true;
                ImageView icon = (ImageView) root.findViewById(R.id.icon);
                if (mItemInfo.primitiveId != 0) {
                    icon.setImageResource(mItemInfo.primitiveId);
                } else {
                    icon.setImageBitmap(WatermarkUtil.getBitmapByFileUrl(mItemInfo.primitiveUrl));
                }
                break;

            default:
                throw new IllegalStateException("parseLayout: layout error!");
        }

        int textColor = 0;
        if (mItemInfo.colorId != 0) {
            textColor = getContext().getResources().getColor(mItemInfo.colorId);
        } else {
            textColor = mItemInfo.color;
        }
        long dateTaken = System.currentTimeMillis();
        Date date = new Date(dateTaken);
        String pattern = "yyyy-MM-dd";
        SimpleDateFormat format = new SimpleDateFormat(pattern);
        String time = format.format(date);
        TextView text = (TextView) root.findViewById(R.id.time);
        text.setText(time);
        text.setTextColor(textColor);

        // set city
        TextView city = (TextView) root.findViewById(R.id.city);
        if (city != null) {
            city.setTextColor(textColor);

            String addr = mWatermarkMode.getCurrentAddr();
            if (addr != null) {
                city.setText(addr);
            }
        }
    }

    private void getPreviewItemBounds(View v, Rect outRect) {
        Matrix m = v.getMatrix();
        int l = v.getLeft();
        int t = v.getTop();

        if (m.isIdentity()) {
            outRect.set(l, t, v.getRight(), v.getBottom());
        } else {
            RectF r = new RectF(0, 0, v.getWidth(), v.getHeight());
            m.mapRect(r);
            outRect.set((int) r.left + l, (int) r.top + t, (int) r.right + l, (int) r.bottom + t);
        }
        
        float scale = mWatermarkMode.getPreviewScale();
        if (scale != 1.0f) {
        	outRect.left = (int) (outRect.left * scale + 0.5f);
        	outRect.top = (int) (outRect.top * scale + 0.5f);
        	outRect.right = (int) (outRect.right * scale + 0.5f);
        	outRect.bottom = (int) (outRect.bottom * scale + 0.5f);
        }
        // azmohan
        //outRect.scale();
        Log.i(TAG, "getPreviewItemBounds(): out rect bound = " + outRect);
    }

    private SpannableStringBuilder getNoteSpannable(int inputCount) {
        String str = "(" + inputCount + "/" + EDIT_TEXT_MAX_LENGTH + ")";
        SpannableStringBuilder strBuilder = new SpannableStringBuilder(str);
        strBuilder.setSpan(new ForegroundColorSpan(mInputCountColor), 1,
                1 + String.valueOf(inputCount).length(), Spannable.SPAN_EXCLUSIVE_EXCLUSIVE);

        return strBuilder;
    }

    private void inputNoteDialog() {
        final Context context = getContext();
        final EditText inputServer = new EditText(context);
        inputServer.setText(mEditNoteText);
        inputServer.setTextColor(Color.BLACK);
        inputServer.setSelectAllOnFocus(true);
        inputServer.setFocusableInTouchMode(true);
        inputServer.setBackground(null);

        LayoutInflater inflater = LayoutInflater.from(getContext());
        View titlePanel = inflater.inflate(R.layout.watermark_note_edit_title_panel, null);
        final TextView numView = (TextView) titlePanel.findViewById(R.id.num);
        numView.setText(getNoteSpannable(mEditNoteText.length()));

        // limit text length
        inputServer.setFilters(new InputFilter[] {
            new InputFilter.LengthFilter(EDIT_TEXT_MAX_LENGTH)
        });
        inputServer.setGravity(Gravity.START);
        inputServer.addTextChangedListener(new TextWatcher() {
            @Override
            public void onTextChanged(CharSequence s, int start, int before, int count) {
            }

            @Override
            public void beforeTextChanged(CharSequence s, int start, int count, int after) {
            }

            @Override
            public void afterTextChanged(Editable s) {
                numView.setText(getNoteSpannable(s.length()));
            }
        });
        inputServer.setHeight(getResources().getDimensionPixelSize(R.dimen.dialog_input_height));

        postDelayed(new Runnable() {
            @Override
            public void run() {
                InputMethodManager inputManager = (InputMethodManager) context.getSystemService(Context.INPUT_METHOD_SERVICE);
                inputManager.showSoftInput(inputServer, 0);
            }
        }, 300);
        Log.i("theme",
                "theme = "
                        + mContext.getResources().getIdentifier("Transparent2", "style",
                                mContext.getPackageName()));
        AlertDialog.Builder builder = mCamera.getAlertDialog();
        builder.setCustomTitle(titlePanel).setView(inputServer)
                .setNegativeButton(context.getString(R.string.watermark_edit_note_cancel), null);
        builder.setPositiveButton(context.getString(R.string.watermark_edit_note_done),
                new DialogInterface.OnClickListener() {
                    public void onClick(DialogInterface dialog, int which) {
                        mEditNoteText = inputServer.getText().toString();
                        invalidate();
                    }
                });
        builder.show();
    }

    private void checkForLongPress() {
        Log.i(TAG, "checkForLongPress()...");

        removeCallbacks(mLongPressRunnable);
        postDelayed(mLongPressRunnable, LONG_PRESS_TIMEOUT);
    }

    private void resetState() {
        Log.i(TAG, "resetState()...");

        mState = IDLE;
        getParent().requestDisallowInterceptTouchEvent(false);
        removeCallbacks(mLongPressRunnable);
        mWatermarkMode.longPressPreview(false);
    }

    /*
     * private void onTouchFocus(float x, float y) { if (mCamera.getGLRoot() ==
     * null) { return; } // Do the inverse transform of the touch coordinates.
     * Matrix m = mCamera.getGLRoot().getCompensationMatrix(); Matrix inv = new
     * Matrix(); m.invert(inv); float[] pts = new float[] { x, y };
     * inv.mapPoints(pts); mCamera.singleTapUp(null, (int) (pts[0] + 0.5f),
     * (int) (pts[1] + 0.5f)); }
     */

    private Runnable mLongPressRunnable = new Runnable() {
        @Override
        public void run() {
            // TODO long press
            mState = LONG_CLICK;
            WatermarkPageView.this.getParent().requestDisallowInterceptTouchEvent(true);
            // vibration effect
            Vibrator vibrator = (Vibrator) mContext.getSystemService(Service.VIBRATOR_SERVICE);
            vibrator.vibrate(new long[] {
                    0, 50, 50, 100, 50
            }, -1);
            // alpha effect
            mWatermarkMode.longPressPreview(true);
        }
    };

}
